package com.rpcfx.transports;

import com.rpcfx.api.RpcfxException;
import com.rpcfx.api.RpcfxRequest;
import com.rpcfx.api.RpcfxResponse;
import com.rpcfx.api.Serialization;
import com.rpcfx.api.spi.ProtobufSerialization;
import com.rpcfx.server.RpcfxInvoker;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpUtil;
import io.netty.util.ReferenceCountUtil;

import static io.netty.handler.codec.http.HttpResponseStatus.NO_CONTENT;
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;

public class HttpHandler extends ChannelInboundHandlerAdapter {

    private RpcfxInvoker rpcfxInvoker;


    public HttpHandler(RpcfxInvoker rpcfxInvoker) {
        this.rpcfxInvoker = rpcfxInvoker;
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        try {
            //logger.info("channelRead流量接口请求开始，时间为{}", startTime);
            FullHttpRequest fullRequest = (FullHttpRequest) msg;
            String uri = fullRequest.uri();
            //logger.info("接收到的请求url为{}", uri);
            ByteBuf content = fullRequest.content();
            byte[] cs = new byte[content.readableBytes()];
            content.readBytes(cs);
            Serialization serialization = new ProtobufSerialization();
            TransportParam transportParam = (TransportParam) serialization.deserialize(cs);
            RpcfxRequest request = new RpcfxRequest();
            request.setMethod(transportParam.getMethodName());
            request.setServiceClass(uri.substring(uri.lastIndexOf("/") + 1));
            request.setParams(transportParam.getArgs());
            RpcfxResponse rpcfxResponse = rpcfxInvoker.invoke(request);
            handler(fullRequest, ctx, rpcfxResponse);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            ReferenceCountUtil.release(msg);
        }
    }

    private void handler(FullHttpRequest fullRequest, ChannelHandlerContext ctx, RpcfxResponse rpcfxResponse) {
        FullHttpResponse response = null;
        Object result = null;
        try {

            if (rpcfxResponse.isSuccess()) {
                result = rpcfxResponse.getData();
            } else {
                if (rpcfxResponse.getRpcfxException() != null) {
                    result = rpcfxResponse.getRpcfxException();
                } else {
                    result = new RpcfxException(-1, "内部错误");
                }
            }
            Serialization serialization = new ProtobufSerialization();
            byte[] resultBytes = serialization.serialize(result);
            response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(resultBytes));
            response.headers().set("Content-Type", "application/octet-stream");
            response.headers().setInt("Content-Length", response.content().readableBytes());

        } catch (Exception e) {
            System.out.println("处理出错:" + e.getMessage());
            response = new DefaultFullHttpResponse(HTTP_1_1, NO_CONTENT);
        } finally {
            if (fullRequest != null) {
                if (!HttpUtil.isKeepAlive(fullRequest)) {
                    ctx.write(response).addListener(ChannelFutureListener.CLOSE);
                } else {
                    //   response.headers().set(CONNECTION, KEEP_ALIVE);
                    ctx.write(response);
                }
                ctx.flush();
                System.out.println("发送了 "+ result);
            }
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }

}
